package tool

import (
	"context"
	"fmt"
	"io"
	"net/http"
	"strings"
	"sync"
	"time"

	"openmanus/llm"
	"openmanus/tool/search"

	logger "github.com/axcom/ninego/log"
	"golang.org/x/net/html"
	"golang.org/x/net/html/atom"
)

// SearchResult 表示单个搜索结果
type SearchResult struct {
	Position    int    `json:"position"`
	URL         string `json:"url"`
	Title       string `json:"title"`
	Description string `json:"description"`
	Source      string `json:"source"`
	RawContent  string `json:"raw_content,omitempty"`
}

// SearchMetadata 搜索操作的元数据
type SearchMetadata struct {
	TotalResults int    `json:"total_results"`
	Language     string `json:"language"`
	Country      string `json:"country"`
}

// SearchResponse Web搜索工具的结构化响应
type SearchResponse struct {
	*ToolResult
	Query    string          `json:"query"`
	Results  []SearchResult  `json:"results"`
	Metadata *SearchMetadata `json:"metadata,omitempty"`
}

// WebContentFetcher 获取网页内容的工具类
type WebContentFetcher struct{}

// NewWebContentFetcher 创建新的内容获取器
func NewWebContentFetcher() *WebContentFetcher {
	return &WebContentFetcher{}
}

// FetchContent 获取并提取网页的主要内容
func (wcf *WebContentFetcher) FetchContent(url string, timeout int) string {
	ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
	defer cancel()

	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
	if err != nil {
		logger.Errorf("Failed to create request %v %v", url, err)
		return ""
	}

	req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		logger.Errorf("Failed to fetch content %v %v", url, err)
		return ""
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		logger.Warn("Failed to fetch content", "url", url, "status")
		return ""
	}

	// 解析HTML
	return wcf.extractText(resp.Body)
}

// extractText 从HTML中提取文本内容
func (wcf *WebContentFetcher) extractText(r io.Reader) string {
	z := html.NewTokenizer(r)
	var textBuilder strings.Builder
	inBody := false

	for {
		tokenType := z.Next()

		switch tokenType {
		case html.ErrorToken:
			return wcf.cleanText(textBuilder.String())
		case html.StartTagToken:
			t := z.Token()
			if t.DataAtom == atom.Body {
				inBody = true
			}
			// 跳过脚本和样式
			if t.DataAtom == atom.Script || t.DataAtom == atom.Style {
				// 跳过直到结束标签
				wcf.skipUntilEndTag(z, t.DataAtom)
			}
		case html.EndTagToken:
			t := z.Token()
			if t.DataAtom == atom.Body {
				inBody = false
			}
		case html.TextToken:
			if inBody {
				textBuilder.WriteString(z.Token().Data)
			}
		}
	}
}

// skipUntilEndTag 跳过直到遇到结束标签
func (wcf *WebContentFetcher) skipUntilEndTag(z *html.Tokenizer, tag atom.Atom) {
	depth := 1
	for depth > 0 {
		tokenType := z.Next()
		switch tokenType {
		case html.ErrorToken:
			return
		case html.StartTagToken:
			if z.Token().DataAtom == tag {
				depth++
			}
		case html.EndTagToken:
			if z.Token().DataAtom == tag {
				depth--
			}
		}
	}
}

// cleanText 清理文本内容
func (wcf *WebContentFetcher) cleanText(text string) string {
	// 移除多余的空白字符
	lines := strings.Split(text, "\n")
	var cleanedLines []string
	for _, line := range lines {
		trimmed := strings.TrimSpace(line)
		if trimmed != "" {
			cleanedLines = append(cleanedLines, trimmed)
		}
	}

	cleaned := strings.Join(cleanedLines, " ")
	// 限制大小为10KB
	if len(cleaned) > 10000 {
		cleaned = cleaned[:10000]
	}

	return cleaned
}

// WebSearchEngine 搜索引擎接口
type WebSearchEngine interface {
	PerformSearch(query string, numResults int, lang, country string) []SearchItem
}

// SearchItem 搜索结果项
type SearchItem struct {
	URL         string
	Title       string
	Description string
}

// WebSearch Web搜索工具
type WebSearch struct {
	*ToolBase
	searchEngines  map[string]WebSearchEngine
	contentFetcher *WebContentFetcher
}

// NewWebSearch 创建新的WebSearch工具
func NewWebSearch() *WebSearch {
	parameters := llm.Schema{
		Type: "object",
		Properties: map[string]interface{}{
			"query": map[string]interface{}{
				"type":        "string",
				"description": "(required) The search query to submit to the search engine.",
			},
			"num_results": map[string]interface{}{
				"type":        "integer",
				"description": "(optional) The number of search results to return. Default is 5.",
				"default":     5,
			},
			"lang": map[string]interface{}{
				"type":        "string",
				"description": "(optional) Language code for search results (default: en).",
				"default":     "en",
			},
			"country": map[string]interface{}{
				"type":        "string",
				"description": "(optional) Country code for search results (default: us).",
				"default":     "us",
			},
			"fetch_content": map[string]interface{}{
				"type":        "boolean",
				"description": "(optional) Whether to fetch full content from result pages. Default is false.",
				"default":     false,
			},
		},
		Required: []string{"query"},
	}

	return &WebSearch{
		ToolBase:       NewToolBase("web_search", "Search the web for real-time information about any topic.\nThis tool returns comprehensive search results with relevant information, URLs, titles, and descriptions.\nIf the primary search engine fails, it automatically falls back to alternative engines.", parameters),
		searchEngines:  make(map[string]WebSearchEngine),
		contentFetcher: NewWebContentFetcher(),
	}
}

// Execute 执行Web搜索
func (ws *WebSearch) Execute(params map[string]interface{}) (*ToolResult, error) {
	query, ok := params["query"].(string)
	if !ok || query == "" {
		return FailResponse("Query is required"), nil
	}

	numResults := 5
	if nr, ok := params["num_results"].(float64); ok {
		numResults = int(nr)
	}

	lang := "en"
	if l, ok := params["lang"].(string); ok && l != "" {
		lang = l
	}

	country := "us"
	if c, ok := params["country"].(string); ok && c != "" {
		country = c
	}

	fetchContent := false
	if fc, ok := params["fetch_content"].(bool); ok {
		fetchContent = fc
	}

	// 使用默认的搜索引擎顺序
	engineOrder := []string{"baidu", "cnbing", "bing", "csdn"}
	var results []SearchResult

	// 尝试所有搜索引擎
	for _, engineName := range engineOrder {
		logger.Info("Attempting search", "engine", engineName, "query", query)
		results = ws.ExecSearchResults(query, numResults, engineName)
		if len(results) > 0 {
			break
		}
	}
	if len(results) == 0 {
		return FailResponse("All search engines failed to return results"), nil
	}

	// 获取内容（如果需要）
	if fetchContent {
		results = ws.fetchContentForResults(results)
	}

	// 构建响应文本
	response := ws.buildSearchResponseText(query, results, lang, country)

	return SuccessResponse(response), nil
}

// 执行搜索返回结果
func (ws *WebSearch) ExecSearchResults(query string, numResults int, source string) []SearchResult {
	results := make([]SearchResult, 0, numResults)
	switch source {
	case "bing":
		res, err := search.SearchBing(query, numResults)
		if err != nil {
			logger.Error("Search Error:", err)
			return []SearchResult{}
		}
		for i := 0; i < len(res); i++ {
			result := SearchResult{
				Position:    i + 1,
				URL:         res[i].URL,
				Title:       res[i].Title,
				Description: res[i].Description,
				Source:      source,
			}
			results = append(results, result)
		}
	case "cnbing":
		res, err := search.SearchCnBing(query, numResults)
		if err != nil {
			logger.Error("Search Error:", err)
			return []SearchResult{}
		}
		for i := 0; i < len(res); i++ {
			result := SearchResult{
				Position:    i + 1,
				URL:         res[i].Link,
				Title:       res[i].Title,
				Description: res[i].Snippet,
				Source:      source,
			}
			results = append(results, result)
		}
	case "csdn":
		res, err := search.SearchCsdn(query, numResults)
		if err != nil {
			logger.Error("Search Error:", err)
			return []SearchResult{}
		}
		for i := 0; i < len(res); i++ {
			result := SearchResult{
				Position:    i + 1,
				URL:         res[i].URL,
				Title:       res[i].Title,
				Description: res[i].Description,
				Source:      source,
			}
			results = append(results, result)
		}
	default: // "baidu"
		res, err := search.SearchBaidu(query, numResults)
		if err != nil {
			logger.Error("Search Error:", err)
			return []SearchResult{}
		}
		for i := 0; i < len(res); i++ {
			result := SearchResult{
				Position:    i + 1,
				URL:         res[i].URL,
				Title:       res[i].Title,
				Description: res[i].Description,
				Source:      source,
			}
			results = append(results, result)
		}
	}

	return results
}

// fetchContentForResults 为搜索结果获取内容
func (ws *WebSearch) fetchContentForResults(results []SearchResult) []SearchResult {
	var wg sync.WaitGroup
	mutex := &sync.Mutex{}

	for i := range results {
		wg.Add(1)
		go func(idx int) {
			defer wg.Done()
			content := ws.contentFetcher.FetchContent(results[idx].URL, 10)
			if content != "" {
				mutex.Lock()
				results[idx].RawContent = content
				mutex.Unlock()
			}
		}(i)
	}

	wg.Wait()
	return results
}

// buildSearchResponseText 构建搜索响应文本
func (ws *WebSearch) buildSearchResponseText(query string, results []SearchResult, lang, country string) string {
	var builder strings.Builder
	builder.WriteString(fmt.Sprintf("Search results for '%s':\n", query))

	for i, result := range results {
		title := result.Title
		if title == "" {
			title = "No title"
		}
		builder.WriteString(fmt.Sprintf("\n%d. %s\n", i+1, title))
		builder.WriteString(fmt.Sprintf("   URL: %s\n", result.URL))
		if result.Description != "" {
			builder.WriteString(fmt.Sprintf("   Description: %s\n", result.Description))
		}
		if result.RawContent != "" {
			preview := result.RawContent
			if len(preview) > 1000 {
				preview = preview[:1000] + "..."
			}
			preview = strings.ReplaceAll(preview, "\n", " ")
			builder.WriteString(fmt.Sprintf("   Content: %s\n", preview))
		}
	}

	builder.WriteString("\nMetadata:")
	builder.WriteString(fmt.Sprintf("\n- Total results: %d", len(results)))
	builder.WriteString(fmt.Sprintf("\n- Language: %s", lang))
	builder.WriteString(fmt.Sprintf("\n- Country: %s", country))

	return builder.String()
}
